package com.t3go.t3_map.utils;

import android.util.Pair;

import com.shareware.common.utils.LogExtKt;
import com.t3go.passenger.base.utils.DensityUtil;
import com.t3go.t3_map.R;
import com.t3map.api.map.T3Map;
import com.t3map.api.map.entity.TrafficInfo;
import com.t3map.api.map.model.T3BitmapDescriptor;
import com.t3map.api.map.model.T3BitmapDescriptorFactory;
import com.t3map.api.map.model.T3LatLng;
import com.t3map.api.map.model.T3Polyline;
import com.t3map.api.map.model.T3PolylineOptions;
import com.t3map.api.map.utils.T3MapUtils;
import com.t3map.api.map.utils.T3SpatialRelationUtil;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

/**
 * 路线工具类
 */
public class PolylineUtils {

    private static final String TAG = "RouteUtils";

    /**
     * 路线的纹理数组
     */
    public static final Integer[] TEXTURE_RES_ID_ARRAY = new Integer[]{R.drawable.icon_route_unkown,
            R.drawable.icon_route_green, R.drawable.icon_route_slow,
            R.drawable.icon_route_jam, R.drawable.icon_route_veryjam};

    /**
     * 未选择路线的纹理数组（保证与上述数组顺序对应）
     */
    public static final Integer[] TEXTURE_RES_ID_UNSELECTED_ARRAY = new Integer[]{R.drawable.icon_route_unkown_unselected,
            R.drawable.icon_route_green_unselect, R.drawable.icon_route_slow_unselected,
            R.drawable.icon_route_jam_unselected, R.drawable.icon_route_veryjam_unselected};


    public static T3Polyline addPolyline(T3Map map) {


        return null;
    }


    /**
     * 根据搜索算路的结果，在地图上画路线，包括交通拥堵状况
     *
     * @param t3map       地图
     * @param trafficList 路线及交通状况
     * @return 地图画的线
     */
    public static T3Polyline drawLine(T3Map t3map, List<TrafficInfo> trafficList) {
        if (t3map == null || trafficList == null) {
            return null;
        }
        List<T3LatLng> pointList = new ArrayList<>();
        List<Integer> textureIndex = new ArrayList<>();
        for (TrafficInfo traffic : trafficList) {
            if (traffic == null || traffic.getPolyline() == null) {
                continue;
            }

            for (T3LatLng latLng : traffic.getPolyline()) {
                if (latLng == null) {
                    continue;
                }
                pointList.add(latLng);
                textureIndex.add(statusToIndex(traffic.getStatus()));
            }
        }

        List<T3BitmapDescriptor> texturesList = new ArrayList<>();
        for (Integer resId : TEXTURE_RES_ID_ARRAY) {
            texturesList.add(T3BitmapDescriptorFactory.fromResource(resId));
        }

        T3PolylineOptions polylineOptions = new T3PolylineOptions()
                .addAll(pointList)
                .width(DensityUtil.dp2px(20))
                .setCustomTextureIndex(textureIndex)
                .setCustomTextureList(texturesList);

        return t3map.addPolyline(polylineOptions);
    }

    public static void updateLine(T3Polyline t3Polyline, List<TrafficInfo> trafficList) {
        if (t3Polyline == null || trafficList == null) {
            return;
        }
        LogExtKt.log(TAG, "updateLine:" + trafficList);

        List<T3LatLng> pointList = new ArrayList<>();
        List<Integer> textureIndex = new ArrayList<>();
        for (TrafficInfo traffic : trafficList) {
            if (traffic == null || traffic.getPolyline() == null) {
                continue;
            }

            for (T3LatLng latLng : traffic.getPolyline()) {
                if (latLng == null) {
                    continue;
                }
                pointList.add(latLng);
                textureIndex.add(statusToIndex(traffic.getStatus()));
            }
        }

        List<T3BitmapDescriptor> texturesList = new ArrayList<>();
        for (Integer resId : TEXTURE_RES_ID_ARRAY) {
            texturesList.add(T3BitmapDescriptorFactory.fromResource(resId));
        }


        t3Polyline.setPoints(pointList);
        t3Polyline.setCustomTextureIndex(textureIndex);
        t3Polyline.setCustomTextureList(texturesList);
    }

    public static T3Polyline drawGisRoute(T3Map t3map, String polyline, String traffic, String relayLine, String relayTraffic) {
        if (t3map == null) {
            LogExtKt.log(TAG, "drawGisRoute t3map is null return");
            return null;
        }

        List<T3LatLng> points = MapDataUtil.parseLngLat(polyline);
        List<T3LatLng> relayPoints = MapDataUtil.parseLngLat(relayLine);
        if (relayPoints.size() > 0) {
            LogExtKt.log(TAG, "添加接力单路线" + relayLine);
            points.addAll(relayPoints);
        }

        if (points.size() == 0) {
            LogExtKt.log(TAG, "route data has wrong, please check:" + polyline);
            return null;
        }

        List<T3BitmapDescriptor> texturesList = new ArrayList<>();
        for (Integer resId : TEXTURE_RES_ID_ARRAY) {
            texturesList.add(T3BitmapDescriptorFactory.fromResource(resId));
        }

        List<Integer> textureIndex = new ArrayList<>();
        TreeMap<Integer, Integer> trafficLevel = MapDataUtil.parseTrafficLevel(traffic);
        TreeMap<Integer, Integer> relayTrafficLevel = MapDataUtil.parseTrafficLevel(points.size(), relayTraffic);
        trafficLevel.putAll(relayTrafficLevel);

        if (trafficLevel.size() == 0) {
            for (int i = 0; i < points.size(); i++) {
                textureIndex.add(1);
            }
        } else {
            int trafficCount = 0;
            for (Map.Entry<Integer, Integer> entry : trafficLevel.entrySet()) {
                for (int i = trafficCount; i < points.size(); i++) {
                    if (i < entry.getKey() && entry.getValue() >= 0 && entry.getValue() < 5) {
                        // 接口下发的交通状态值 -> TrafficLevel枚举 -> 对应纹理List中的Index
                        TrafficLevel level = TrafficLevel.getTrafficLevel(entry.getValue());
                        Integer index = PolylineUtils.levelToIndex(level);
                        textureIndex.add(index);
                    }
                }
                trafficCount = entry.getKey();
            }
        }

        T3PolylineOptions polylineOptions = new T3PolylineOptions()
                .addAll(points)
                .width(DensityUtil.dp2px(20))
                .setCustomTextureIndex(textureIndex)
                .setCustomTextureList(texturesList)
                .zIndex(2);
        return t3map.addPolyline(polylineOptions);
    }

    public static void updateGisRoute(T3Polyline t3Polyline, String polyline, String traffic, String relayLine, String relayTraffic) {
        if (t3Polyline == null) {
            LogExtKt.log(TAG, "updateGisRoute T3Polyline is null return");
            return;
        }

        List<T3LatLng> points = MapDataUtil.parseLngLat(polyline);
        List<T3LatLng> relayPoints = MapDataUtil.parseLngLat(relayLine);
        if (relayPoints.size() > 0) {
            LogExtKt.log(TAG, "updateGisRoute -> 添加接力单路线" + relayLine);
            points.addAll(relayPoints);
        }
        if (points.size() == 0) {
            LogExtKt.log(TAG, "route data has wrong, please check:" + polyline);
            return;
        }

        List<T3BitmapDescriptor> texturesList = new ArrayList<>();
        for (Integer resId : TEXTURE_RES_ID_ARRAY) {
            texturesList.add(T3BitmapDescriptorFactory.fromResource(resId));
        }

        List<Integer> textureIndex = new ArrayList<>();
        Map<Integer, Integer> trafficLevel = MapDataUtil.parseTrafficLevel(traffic);
        TreeMap<Integer, Integer> relayTrafficLevel = MapDataUtil.parseTrafficLevel(points.size(), relayTraffic);
        trafficLevel.putAll(relayTrafficLevel);

        if (trafficLevel.size() == 0) {
            for (int i = 0; i < points.size(); i++) {
                textureIndex.add(1);
            }
        } else {
            int trafficCount = 0;
            for (Map.Entry<Integer, Integer> entry : trafficLevel.entrySet()) {
                for (int i = trafficCount; i < points.size(); i++) {
                    if (i < entry.getKey() && entry.getValue() >= 0 && entry.getValue() < 5) {
                        // 接口下发的交通状态值 -> TrafficLevel枚举 -> 对应纹理List中的Index
                        TrafficLevel level = TrafficLevel.getTrafficLevel(entry.getValue());
                        Integer index = PolylineUtils.levelToIndex(level);
                        textureIndex.add(index);
                    }
                }
                trafficCount = entry.getKey();
            }
        }

        t3Polyline.setPoints(points);
        t3Polyline.setCustomTextureList(texturesList);
        t3Polyline.setCustomTextureIndex(textureIndex);
    }

    /**
     * 高德SDK返回的交通状态 转化为 对应纹理列表中的Index
     *
     * @param trafficStatus 交通状态，详情见
     * @return index
     */
    private static int statusToIndex(int trafficStatus) {
        List<Integer> textureResList = Arrays.asList(TEXTURE_RES_ID_ARRAY);
        return textureResList.indexOf(getTrafficResId(trafficStatus));
    }

    /**
     * T3服务器接口定义的交通状态 转化为 对应纹理列表中的Index
     *
     * @param level 交通状态，详情见
     * @return index
     */
    public static int levelToIndex(TrafficLevel level) {
        List<Integer> textureResList = Arrays.asList(TEXTURE_RES_ID_ARRAY);
        return textureResList.indexOf(getTrafficResId(level));
    }

    /**
     * 交通状态 对应的 resId
     *
     * @param trafficStatus 交通状态
     * @return resId
     */
    private static Integer getTrafficResId(int trafficStatus) {
        switch (trafficStatus) {
            case TrafficInfo.TRAFFIC_STATUS_UNKNOWN:
                return R.drawable.icon_route_unkown;
            case TrafficInfo.TRAFFIC_STATUS_SMOOTH:
                return R.drawable.icon_route_green;
            case TrafficInfo.TRAFFIC_STATUS_SLOW:
                return R.drawable.icon_route_slow;
            case TrafficInfo.TRAFFIC_STATUS_JAM:
                return R.drawable.icon_route_jam;
            case TrafficInfo.TRAFFIC_STATUS_VERY_JAM:
                return R.drawable.icon_route_veryjam;

        }
        return R.drawable.icon_route_unkown;
    }

    /**
     * 交通状态 对应的 resId
     *
     * @param level 交通状态
     * @return resId
     */
    private static Integer getTrafficResId(TrafficLevel level) {
        switch (level) {
            case UNKNOWN:
                return R.drawable.icon_route_unkown;
            case SMOOTH:
                return R.drawable.icon_route_green;
            case SLOW:
                return R.drawable.icon_route_slow;
            case JAM:
                return R.drawable.icon_route_jam;
            case VERY_JAM:
                return R.drawable.icon_route_veryjam;

        }
        return R.drawable.icon_route_unkown;
    }

    /**
     * 获取小车移动轨迹
     *
     * @param points      路线
     * @param carLocation 小车当前位置
     * @param newLatLng   小车新位置
     */
    public static List<T3LatLng> getCarMovePoints(List<T3LatLng> points, T3LatLng carLocation, T3LatLng newLatLng) {

        //小车要移动的路线集合
        List<T3LatLng> movePoints = new ArrayList<>();

        if (carLocation == null || newLatLng == null) {
            return movePoints;
        }

        if (points == null || points.size() == 0) {
            movePoints.add(carLocation);
            movePoints.add(newLatLng);
            return movePoints;
        }
        movePoints.add(carLocation);

        // 目前小车位置在路线上最近的点
        Pair<Integer, T3LatLng> nowCarPair = T3SpatialRelationUtil.calShortestDistancePoint(points, carLocation);

        // 新的小车位置在路线上最近的点
        Pair<Integer, T3LatLng> targetCarPair = T3SpatialRelationUtil.calShortestDistancePoint(points, newLatLng);
        LogExtKt.log(TAG, "   nowCarPair = " + nowCarPair);
        LogExtKt.log(TAG, "targetCarPair = " + targetCarPair);

        // 兜底逻辑，如果新的小车位置超出路线100m，则需要重新算路
        if (targetCarPair != null && T3MapUtils.calculateLineDistance(newLatLng, targetCarPair.second) > 100) {
            float carToLineDistance = T3MapUtils.calculateLineDistance(newLatLng, targetCarPair.second);
            LogExtKt.log(TAG, "carToLine distance:" + carToLineDistance + ", move direct");
            movePoints.add(newLatLng);
        } else {
            if (targetCarPair == null || nowCarPair == null) {
                LogExtKt.log(TAG, "pair is null, move direct");
                movePoints.add(newLatLng);
            } else {
                // 当前小车位置在路线上的index
                if (nowCarPair.first.equals(targetCarPair.first)) {
                    // 如果当前index 和目标index相同，则直接在具体经纬度之间移动
                    LogExtKt.log(TAG, "index same, move second");
                    movePoints.add(targetCarPair.second);
                } else if (nowCarPair.first > targetCarPair.first) {
                    // 如果当前index 大于 目标index，则认为计算是有问题的。此时移动到给定位置（或者也可以丢掉该次数据，看效果）
                    LogExtKt.log(TAG, "index calculate error, move direct");
                    movePoints.add(newLatLng);
                } else {
                    // 如果当前index 小于 目标index，则取两个index之间的路线，同时最后加上目标经纬度，作为移动的路线
                    int startIndex;
                    if (nowCarPair.first < points.size() - 1) {
                        startIndex = nowCarPair.first + 1;
                    } else {
                        startIndex = points.size() - 1;
                    }
                    // 新的小车位置在路线上的 index 的下一个index
                    int endIndex;
                    if (targetCarPair.first < points.size()) {
                        endIndex = targetCarPair.first + 1;
                    } else {
                        endIndex = points.size();
                    }
                    // 要取 sublist 的 startIndex（包含） 和 endIndex（不包含） 之间的值，因此，startIndex最大为size-1, endIndex最大为size
                    // 取出这两个index 之间的路线，即为小车在这次5S内需要平滑移动的点位路线
                    movePoints.addAll(points.subList(startIndex, endIndex));
                    movePoints.add(targetCarPair.second);
                    LogExtKt.log(TAG, "index change startIndex:" + startIndex + ", endIndex:" + endIndex + ", move index and target latLng");
                }
            }
        }
        return movePoints;
    }

    public static List<Integer> getTextureIndex(List<T3LatLng> points, Map<Integer, Integer> trafficLevel) {
        if (points == null || trafficLevel == null) {
            return null;
        }
        List<Integer> textureIndex = new ArrayList<>(points.size());
        int trafficCount = 0;
        for (Map.Entry<Integer, Integer> entry : trafficLevel.entrySet()) {
            for (int i = trafficCount; i < points.size(); i++) {
                if (i < entry.getKey()) {
                    TrafficLevel level = TrafficLevel.getTrafficLevel(entry.getValue());
                    Integer index = levelToIndex(level);
                    textureIndex.add(index);
                }
            }
            trafficCount = entry.getKey();
        }
        return textureIndex;
    }


    public static List<T3BitmapDescriptor> getTexturesList(boolean selected) {
        Integer[] list = selected ? TEXTURE_RES_ID_ARRAY : TEXTURE_RES_ID_UNSELECTED_ARRAY;
        List<T3BitmapDescriptor> texturesList = new ArrayList<>();
        for (Integer resId : list) {
            texturesList.add(T3BitmapDescriptorFactory.fromResource(resId));
        }
        return texturesList;
    }
}
